/**
 * 文件处理工具模块
 * 提供文件操作相关的实用功能，包括文件读取、下载、上传、格式转换等
 */

/**
 * 获取文件扩展名
 * @param {string} filename 文件名
 * @returns {string} 文件扩展名（不包含点号）
 */
export function getFileExtension(filename) {
  if (typeof filename !== 'string' || !filename) {
    return '';
  }
  const lastDotIndex = filename.lastIndexOf('.');
  return lastDotIndex !== -1 ? filename.slice(lastDotIndex + 1).toLowerCase() : '';
}

/**
 * 获取文件名（不包含扩展名）
 * @param {string} filename 文件名
 * @returns {string} 文件名（不包含扩展名）
 */
export function getFileName(filename) {
  if (typeof filename !== 'string' || !filename) {
    return '';
  }
  const lastDotIndex = filename.lastIndexOf('.');
  const lastSlashIndex = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
  const start = lastSlashIndex + 1;
  const end = lastDotIndex !== -1 ? lastDotIndex : filename.length;
  return filename.slice(start, end);
}

/**
 * 格式化文件大小
 * @param {number} bytes 字节数
 * @param {number} decimals 小数位数，默认2
 * @returns {string} 格式化后的文件大小
 */
export function formatFileSize(bytes, decimals = 2) {
  if (typeof bytes !== 'number' || bytes < 0) {
    return '0 B';
  }

  const k = 1024;
  const dm = decimals < 0 ? 0 : decimals;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

/**
 * 检查文件类型是否为图片
 * @param {string} filename 文件名或扩展名
 * @returns {boolean} 是否为图片文件
 */
export function isImageFile(filename) {
  const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico', 'tiff', 'tif'];
  const ext = getFileExtension(filename);
  return imageExtensions.includes(ext);
}

/**
 * 检查文件类型是否为视频
 * @param {string} filename 文件名或扩展名
 * @returns {boolean} 是否为视频文件
 */
export function isVideoFile(filename) {
  const videoExtensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv', '3gp', 'rm', 'rmvb'];
  const ext = getFileExtension(filename);
  return videoExtensions.includes(ext);
}

/**
 * 检查文件类型是否为音频
 * @param {string} filename 文件名或扩展名
 * @returns {boolean} 是否为音频文件
 */
export function isAudioFile(filename) {
  const audioExtensions = ['mp3', 'wav', 'flac', 'aac', 'ogg', 'wma', 'm4a', 'opus'];
  const ext = getFileExtension(filename);
  return audioExtensions.includes(ext);
}

/**
 * 检查文件类型是否为文档
 * @param {string} filename 文件名或扩展名
 * @returns {boolean} 是否为文档文件
 */
export function isDocumentFile(filename) {
  const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf', 'odt'];
  const ext = getFileExtension(filename);
  return documentExtensions.includes(ext);
}

/**
 * 下载文件
 * @param {string|Blob} data 文件数据（URL或Blob对象）
 * @param {string} filename 文件名
 * @param {string} mimeType MIME类型
 */
export function downloadFile(data, filename, mimeType = 'application/octet-stream') {
  let url;
  let shouldRevoke = false;

  if (data instanceof Blob) {
    url = URL.createObjectURL(data);
    shouldRevoke = true;
  } else if (typeof data === 'string') {
    url = data;
  } else {
    throw new Error('数据类型不支持');
  }

  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  link.style.display = 'none';

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);

  if (shouldRevoke) {
    setTimeout(() => URL.revokeObjectURL(url), 100);
  }
}

/**
 * 下载文本文件
 * @param {string} content 文本内容
 * @param {string} filename 文件名
 * @param {string} mimeType MIME类型
 */
export function downloadTextFile(content, filename, mimeType = 'text/plain') {
  const blob = new Blob([content], { type: mimeType });
  downloadFile(blob, filename, mimeType);
}

/**
 * 下载JSON文件
 * @param {Object} data JSON数据
 * @param {string} filename 文件名
 * @param {boolean} formatted 是否格式化JSON
 */
export function downloadJsonFile(data, filename, formatted = true) {
  const content = formatted ? JSON.stringify(data, null, 2) : JSON.stringify(data);
  downloadTextFile(content, filename, 'application/json');
}

/**
 * 下载CSV文件
 * @param {Array<Array<string>>} data CSV数据（二维数组）
 * @param {string} filename 文件名
 * @param {string} separator 分隔符，默认逗号
 */
export function downloadCsvFile(data, filename, separator = ',') {
  if (!Array.isArray(data) || data.length === 0) {
    throw new Error('CSV数据必须是非空的二维数组');
  }

  const csvContent = data.map(row =>
    row.map(cell => {
      const str = String(cell);
      // 如果包含分隔符、换行符或双引号，需要用双引号包围
      if (str.includes(separator) || str.includes('\n') || str.includes('"')) {
        return '"' + str.replace(/"/g, '""') + '"';
      }
      return str;
    }).join(separator)
  ).join('\n');

  downloadTextFile(csvContent, filename, 'text/csv');
}

/**
 * 读取文件内容
 * @param {File} file 文件对象
 * @param {string} readAs 读取方式：'text', 'dataURL', 'arrayBuffer', 'binaryString'
 * @returns {Promise<string|ArrayBuffer>} 文件内容
 */
export function readFile(file, readAs = 'text') {
  return new Promise((resolve, reject) => {
    if (!(file instanceof File)) {
      reject(new Error('参数必须是File对象'));
      return;
    }

    const reader = new FileReader();
    reader.onload = e => resolve(e.target.result);
    reader.onerror = () => reject(new Error('文件读取失败'));

    switch (readAs) {
      case 'text':
        reader.readAsText(file);
        break;
      case 'dataURL':
        reader.readAsDataURL(file);
        break;
      case 'arrayBuffer':
        reader.readAsArrayBuffer(file);
        break;
      case 'binaryString':
        reader.readAsBinaryString(file);
        break;
      default:
        reject(new Error('不支持的读取方式'));
    }
  });
}

/**
 * 读取文本文件
 * @param {File} file 文件对象
 * @returns {Promise<string>} 文件文本内容
 */
export function readTextFile(file) {
  return readFile(file, 'text');
}

/**
 * 读取JSON文件
 * @param {File} file 文件对象
 * @returns {Promise<Object>} 解析后的JSON对象
 */
export async function readJsonFile(file) {
  const text = await readTextFile(file);
  try {
    return JSON.parse(text);
  } catch (e) {
    throw new Error('JSON文件格式错误');
  }
}

/**
 * 选择文件对话框
 * @param {Object} options 选项
 * @param {string} options.accept 接受的文件类型
 * @param {boolean} options.multiple 是否多选
 * @returns {Promise<FileList>} 选择的文件列表
 */
export function selectFiles(options = {}) {
  return new Promise((resolve, reject) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.style.display = 'none';

    if (options.accept) {
      input.accept = options.accept;
    }
    if (options.multiple) {
      input.multiple = true;
    }

    input.onchange = e => {
      resolve(e.target.files);
      document.body.removeChild(input);
    };

    input.oncancel = () => {
      reject(new Error('用户取消选择'));
      document.body.removeChild(input);
    };

    document.body.appendChild(input);
    input.click();
  });
}

/**
 * 创建文件对象
 * @param {string|ArrayBuffer|Array} data 文件数据
 * @param {string} filename 文件名
 * @param {string} mimeType MIME类型
 * @returns {File} 文件对象
 */
export function createFile(data, filename, mimeType = 'application/octet-stream') {
  if (typeof data === 'string') {
    data = new TextEncoder().encode(data);
  }

  const blob = new Blob([data], { type: mimeType });
  return new File([blob], filename, { type: mimeType });
}

/**
 * 文件转Base64
 * @param {File|Blob} file 文件对象
 * @returns {Promise<string>} Base64字符串
 */
export function fileToBase64(file) {
  return readFile(file, 'dataURL');
}

/**
 * Base64转文件
 * @param {string} base64 Base64字符串
 * @param {string} filename 文件名
 * @returns {File} 文件对象
 */
export function base64ToFile(base64, filename) {
  const arr = base64.split(',');
  const mime = arr[0].match(/:(.*?);/)[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);

  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }

  return new File([u8arr], filename, { type: mime });
}

/**
 * 压缩图片文件
 * @param {File} file 图片文件
 * @param {Object} options 压缩选项
 * @param {number} options.quality 压缩质量 0-1，默认0.8
 * @param {number} options.maxWidth 最大宽度
 * @param {number} options.maxHeight 最大高度
 * @param {string} options.mimeType 输出MIME类型
 * @returns {Promise<File>} 压缩后的文件
 */
export function compressImage(file, options = {}) {
  return new Promise((resolve, reject) => {
    if (!isImageFile(file.name)) {
      reject(new Error('不是图片文件'));
      return;
    }

    const {
      quality = 0.8,
      maxWidth = 1920,
      maxHeight = 1080,
      mimeType = 'image/jpeg'
    } = options;

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const img = new Image();

    img.onload = () => {
      // 计算压缩后的尺寸
      let { width, height } = img;

      if (width > maxWidth) {
        height = (height * maxWidth) / width;
        width = maxWidth;
      }

      if (height > maxHeight) {
        width = (width * maxHeight) / height;
        height = maxHeight;
      }

      canvas.width = width;
      canvas.height = height;

      // 绘制图片
      ctx.drawImage(img, 0, 0, width, height);

      // 转换为Blob
      canvas.toBlob(blob => {
        const compressedFile = new File([blob], file.name, { type: mimeType });
        resolve(compressedFile);
      }, mimeType, quality);
    };

    img.onerror = () => reject(new Error('图片加载失败'));
    img.src = URL.createObjectURL(file);
  });
}

/**
 * 获取文件的MIME类型
 * @param {string} filename 文件名
 * @returns {string} MIME类型
 */
export function getMimeType(filename) {
  const ext = getFileExtension(filename);
  const mimeTypes = {
    // 图片
    'jpg': 'image/jpeg',
    'jpeg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'bmp': 'image/bmp',
    'webp': 'image/webp',
    'svg': 'image/svg+xml',
    'ico': 'image/x-icon',

    // 视频
    'mp4': 'video/mp4',
    'avi': 'video/x-msvideo',
    'mov': 'video/quicktime',
    'wmv': 'video/x-ms-wmv',
    'flv': 'video/x-flv',
    'webm': 'video/webm',

    // 音频
    'mp3': 'audio/mpeg',
    'wav': 'audio/wav',
    'flac': 'audio/flac',
    'aac': 'audio/aac',
    'ogg': 'audio/ogg',

    // 文档
    'pdf': 'application/pdf',
    'doc': 'application/msword',
    'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'xls': 'application/vnd.ms-excel',
    'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'ppt': 'application/vnd.ms-powerpoint',
    'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'txt': 'text/plain',
    'rtf': 'application/rtf',

    // 开发相关
    'html': 'text/html',
    'css': 'text/css',
    'js': 'application/javascript',
    'json': 'application/json',
    'xml': 'application/xml',
    'csv': 'text/csv',

    // 压缩文件
    'zip': 'application/zip',
    'rar': 'application/x-rar-compressed',
    '7z': 'application/x-7z-compressed',
    'tar': 'application/x-tar',
    'gz': 'application/gzip'
  };

  return mimeTypes[ext] || 'application/octet-stream';
}

/**
 * 验证文件大小
 * @param {File} file 文件对象
 * @param {number} maxSize 最大大小（字节）
 * @returns {boolean} 是否符合大小限制
 */
export function validateFileSize(file, maxSize) {
  return file instanceof File && file.size <= maxSize;
}

/**
 * 验证文件类型
 * @param {File} file 文件对象
 * @param {Array<string>} allowedTypes 允许的文件类型（扩展名数组）
 * @returns {boolean} 是否符合类型限制
 */
export function validateFileType(file, allowedTypes) {
  if (!(file instanceof File) || !Array.isArray(allowedTypes)) {
    return false;
  }

  const ext = getFileExtension(file.name);
  return allowedTypes.map(type => type.toLowerCase()).includes(ext);
}